import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';

import 'fluoss_helper.dart';

class FluossUtil implements FluOssHelper {
  MethodChannel _channel;

  Map<String, OssUploadListener> map;

  FluossUtil(this._channel) {
    _channel.setMethodCallHandler((call) {
      String tagName = call.arguments["tag"] as String;
      OssUploadListener callBackListener = getListenerByTag(call);
      print("看看执行方法名字${call.method}");
      if (callBackListener == null) {
        return Future.value("");
      }
      switch (call.method) {
        case "clientError":
          callBackListener.clientError
              ?.call(getValue<String>(call, "errorMessage"));
          map.remove(tagName);
          break;
        case "serverError":
          callBackListener.serverErrorCallBack?.call(ServerError(
              getValue<int>(call, "code"),
              getValue<String>(call, "errorMessage"),
              getValue<String>(call, "hostId")));
          map.remove(tagName);
          break;
        case "completeCallBack":
          callBackListener.upLoadComplete
              .call(getValue<String>(call, "requestId"));
          map.remove(tagName);
          break;
        case "progressCallBack":
          callBackListener.uploadProgressCallBack
              .call(getValue<double>(call, "progress"));
          break;
        case "cancelTask":
          callBackListener
              .cancelTask(getValue<List<Map<String, dynamic>>>(call, "tasks"));
          break;
        default:
          break;
      }
      return Future.value("");
    });
  }

  @override
  Future initOss(
      {@required String endPoint,
      @required String stsServer,
      bool needLog = false,
      NetConfig netConfig}) async {
    if (netConfig == null) netConfig = NetConfig();
    await _channel.invokeMethod("initOss", {
      "endPoint": endPoint,
      "stsServer": stsServer,
      "needLog": needLog,
      "connectOutTime": netConfig.connectOutTime,
      "socketOutTime": netConfig.socketOutTime,
      "maxConcurrencyNum": netConfig.maxConcurrencyNum,
      "retryNum": netConfig.retryNum,
      "needDns": netConfig.needDns,
      "userAgent": netConfig.userAgent,
    });
  }

  @override
  Future upLoadFileByPath(String bucketName, String objectName, String path,
      {@required OssUploadListener ossUploadListener,
      String tag,
      isSign = false}) async {
    print("应该有上传的调用啊");
    if (map == null) {
      map = Map();
    }
    if (tag == null) {
      tag = DateTime.now().toString();
    }
    print("input tag : $tag");
    map.addAll({tag: ossUploadListener});
    await _channel.invokeMethod("uploadFile", {
      "filePath": path,
      "objectName": objectName,
      "bucketName": bucketName,
      "backTag": tag,
      "isSign": isSign
    });
  }

  OssUploadListener getListenerByTag(MethodCall call) {
    String tagName = call.arguments["tag"] as String;
    print("output tag : $tagName");
    if (tagName.isEmpty) {
      return null;
    }
    if (!map.containsKey(tagName)) {
      return null;
    }
    return map[tagName];
  }

  Future<String> getFilePath(String bucketName,String objectName,bool isSign) async {
    return await _channel.invokeMethod("getFilePath",{
      "objectName": objectName,
      "bucketName": bucketName,
      "isSign": isSign
    });
  }

  Future destroyManager(String bucketName,String objectName,bool isSign) async {
    return await _channel.invokeMethod("destroyManager");
  }


  T getValue<T>(MethodCall call, String s) {
    return call.arguments[s] as T;
  }

  @override
  Future cancelTask({String tag, bool cancelAll}) async {
    if (cancelAll) {
      await _channel.invokeMethod("cancelAllTask");
    } else {
      await _channel.invokeMethod("cancelTask", {"backTag": tag});
    }
  }

  @override
  Future customCancelTask({String tag, bool cancelAll}) async {
    if (cancelAll) {
      await _channel.invokeMethod("customCancelAllTask");
    } else {
      await _channel.invokeMethod("customCancelTask", {"backTag": tag});
    }
  }

  @override
  Future customOssUpLoad(String bucketName, String objectName, String path,
      {@required OssUploadListener ossUploadListener, String tag}) async {
    if (map == null) {
      map = Map();
    }
    if (tag == null) {
      tag = DateTime.now().toString();
    }
    map.addAll({tag: ossUploadListener});
    await _channel.invokeMethod("customOssUpload", {
      "filePath": path,
      "objectName": objectName,
      "bucketName": bucketName,
      "backTag": tag
    });
  }

  @override
  Future initCustomOss(
      {String endPoint,
      String sign,
      String stsServer,
      bool needLog,
      NetConfig netConfig}) async {
    if (netConfig == null) netConfig = NetConfig();
    await _channel.invokeMethod("initCustomOss", {
      "endPoint": endPoint,
      "stsServer": stsServer,
      "needLog": needLog,
      "connectOutTime": netConfig.connectOutTime,
      "socketOutTime": netConfig.socketOutTime,
      "maxConcurrencyNum": netConfig.maxConcurrencyNum,
      "retryNum": netConfig.retryNum,
      "needDns": netConfig.needDns,
      "userAgent": netConfig.userAgent,
    });
  }

  @override
  Future buildCustomOssManager() async {
    await _channel.invokeMethod("buildCustomManager");
  }
}

class OssUploadListener {
  ValueChanged<double> uploadProgressCallBack;
  ValueChanged<ServerError> serverErrorCallBack;
  ValueChanged<String> clientError;
  ValueChanged<String> upLoadComplete;
  ValueChanged<List<Map<String, dynamic>>> cancelTask;

  OssUploadListener(
      {@required this.uploadProgressCallBack,
      @required this.serverErrorCallBack,
      @required this.clientError,
      @required this.upLoadComplete,
      @required this.cancelTask});
}

class ServerError {
  int errorCode;
  String errorMessage;
  String hostId;

  ServerError(this.errorCode, this.errorMessage, this.hostId);
}
